//ws服务
const ws = require("ws");
//入口文件
const entryMain = require('./src/entryMain.js')
//队列服务
const { initPAQueue } = require('./src/nodeQueue/queue.js')
const paQueue = initPAQueue(50000); //并发上限50000个任务
//http服务
const douyinWssInfo = require('./src/douyin/wssInfo.js')
const express = require('express');
const bodyParser = require('body-parser'); //json解析
const app = express();
const cors = require('cors');
app.use(cors());
app.use(bodyParser.json())

const config = {
	port: 5858, // ws服务端口
	httpPort: 5880, // http服务端口
};

// 设置全局变量 - 快手客户端列表池
global.ksPool = {};
// 设置全局变量 - 抖音客户端列表池
global.dyPool = {};
// 设置全局变量 - 服务端客户端列表 item = {clientId:客户端id标识, socket:客户端socket对象}
global.clientList = [];
//快手 抖音 获取客户端池
const getClientPool = (soure) => {
	if(soure == 'ks') return global.ksPool; //快手
	if(soure == 'dy') return global.dyPool; //抖音
}

//ws输出 json字符串 data = '数据', soure = '平台ks/dy', type = '消息类型'
const buildStrJSON = (code = 0, msg = '', data = '', soure = 'ks', type = '') => {
	return JSON.stringify({code: Number(code), msg: msg, soure: soure, type: type, data: !data ? [] : data})
}

//打印控制台日志
const consoleLog = (obj, level = 'info') => {
	const isWrite = true;
	return isWrite && console[level](obj);
}

//解析url参数
const handleParseUrl = (url) => {
	var obj = {}
	var arrNew = url.split('?')[1].split('&')
	for (let i = 0; i < arrNew.length; i++) {
		var key = arrNew[i].split('=')[0]
		var value = arrNew[i].split('=')[1]
		//在对象中添加属性
		obj[key] = value
	}
	return obj
}

//ws连接验证 参数是否正确
const ClientVerify = (info, cb) => {
	const params = handleParseUrl(info.req.url)
	if(!params.id || !params.key || !params.soure){
		return cb(false, 403, 'require params id,key,soure');
	}
	//授权
	if(params.key != 'szktor'){
		return cb(false, 403, 'not unauthorized');
	}
	return cb(true, 200, 'success');
}

//创建ws服务
const server = new ws.Server({port: config.port, verifyClient: ClientVerify}, () => {
	console.log(`Websocket Server: ws://127.0.0.1:${config.port}?soure=ks&id=xxx&key=szktor`);
})
server.on('connection', (socket, req) => {
	//解析ws连接地址上的url参数 ?soure=ks/dy&id=xxx&key=xxx
	const params = handleParseUrl(req.url)
	params.soure = params.soure.toLowerCase(); // 转小写 客户端平台标识 ks/dy
	socket.clientId = `${params.soure}-${params.id}`; // 客户端ID
	socket.soure = `${params.soure}`; // 客户端平台标识 ks/dy

	sendMsg(buildStrJSON(200, `您是第${server._server._connections}个连接，已有连接池数量：${global.clientList.length}`, '', socket.soure, 'notice'), socket.clientId)

	// 监听客户端发来的消息...  socket.send(msg);
    socket.on("message", (msg) => {
		consoleLog(`${socket.clientId} 发来消息：${msg}`);
		try{
			const msgJson = JSON.parse(msg)
			if(msgJson.type && msgJson.type == 'ping'){ //心跳包回应客户端 {type: 'ping'}
				sendMsg(buildStrJSON(200, 'success', '', socket.soure, 'ping'), socket.clientId)
			}
		}catch(e){
			sendMsg(buildStrJSON(500, '请发送json格式数据', '', socket.soure), socket.clientId)
		}
    });

    // 监听客户端的关闭 socket 
    socket.on("close", function () {
        //关闭ws连接
		closeSocket(socket.clientId, true);
		consoleLog(`${socket.clientId} 关闭连接`);
    })

	//放到最下在，不然监听消息没有触发
	const oldIdx = global.clientList.findIndex(item => item.socket.clientId === socket.clientId);
	const isExits = oldIdx < 0 ? false : true;
	if(!isExits){
		global.clientList.push({
			socket: socket, // 客户端socket对象
			roomId: params.id, // ws url中的id
			key: params.id, // ws url中的key
			soure: params.soure, // ws url中的soure - 平台标识 ks/dy
			buildStrJSON: buildStrJSON, // 构建json字符串的方法
			sendMsg: sendMsg, // 发送消息的方法
			closeSocket: closeSocket, // 关闭连接的方法
			consoleLog: consoleLog, // 控制台日志输出
			setGlobalData: setGlobalData, //修改全局变量数据
			getGlobalData: getGlobalData, //获取全局变量数据
			getClientPool: getClientPool, //快手 抖音 获取客户端池
			serverConnected: true, // 是否连接 - 客户端连接到本websocket服务标识
			initEntry: null, // 初始化入口方法
		});
		//快手 抖音 初始化客户端池数据
		getClientPool(socket.soure)[socket.clientId] = {client: null, connected: false}
	}
	const newIdx = global.clientList.findIndex(item => item.socket.clientId === socket.clientId && (!item.initEntry || !getClientPool(socket.soure)[socket.clientId].connected));
	if(newIdx > -1){
		// 初始化入口方法
		global.clientList[newIdx].initEntry = new entryMain(global.clientList[newIdx])
	}
});

//ws广播消息  server.clients.forEach
const sendMsg = (msg, clientId) => {
	if(!msg) return;
	if(!clientId){ //向所有发送
		global.clientList.forEach(item => {
			if(item.socket.readyState === ws.OPEN){
				item.socket.send(msg)
			}
		})
		return;
	}
	//向指定id发送
	const clientItem = global.clientList.find(item => item.socket.clientId === clientId);
	if(!clientItem) return
	if(clientItem.socket.readyState === ws.OPEN){
		clientItem.socket.send(msg)
	}
}

//关闭ws连接  server.clients.forEach
const closeSocket = (clientId = '', useDel = true) => {
	if(!clientId){ //关闭所有
		global.clientList.forEach((item, idx) => {
			item.socket && item.socket.close()
			item.serverConnected = false // 是否连接 - 客户端连接到本websocket服务标识
			//快手 抖音 客户端池数据
			if(getClientPool(item.socket.soure)[item.socket.clientId].client){
				getClientPool(item.socket.soure)[item.socket.clientId].client.stop();
			}
			getClientPool(item.socket.soure)[item.socket.clientId] = {client: null, connected: false}
			item.initEntry = null // 初始化入口方法
			//从列表中移除
			if(useDel){
				//快手 抖音 客户端池数据
				delete getClientPool(item.socket.soure)[item.socket.clientId]
				global.clientList.splice(idx, 1);
			}
		})
		return;
	}
	//关闭指定id连接
	const idx = global.clientList.findIndex(item => item.socket.clientId === clientId);
	if(idx < 0) return
	const clientItem = global.clientList[idx];
	clientItem.socket && clientItem.socket.close()
	global.clientList[idx].serverConnected = false // 是否连接 - 客户端连接到本websocket服务标识
	//快手 抖音 客户端池数据
	if(getClientPool(clientItem.socket.soure)[clientItem.socket.clientId].client){
		getClientPool(clientItem.socket.soure)[clientItem.socket.clientId].client.stop();
	}
	getClientPool(clientItem.socket.soure)[clientItem.socket.clientId] = {client: null, connected: false}
	global.clientList[idx].initEntry = null // 初始化入口方法
	//从列表中移除
	if(useDel){
		//快手 抖音 客户端池数据
		delete getClientPool(clientItem.socket.soure)[clientItem.socket.clientId]
		global.clientList.splice(idx, 1);
	}
}

//修改全局变量数据
const setGlobalData = (key, value, clientId) => {
	if(!key) return
	if(!clientId){ //修改所有
		if(['client', 'connected'].includes(key)){ // 快手 抖音 客户端池数据 修改
			global.clientList.forEach((item, idx) => {
				getClientPool(item.socket.soure)[item.socket.clientId][key] = value;
			})
			return true;
		}
		//服务端 客户池数据 修改
		global.clientList.forEach((item, idx) => {
			global.clientList[idx][key] = value;
		})
		return true;
	}
	//修改指定id
	const idx = global.clientList.findIndex(item => item.socket.clientId === clientId);
	if(idx < 0 || !global.clientList[idx]) return false;
	// 快手 抖音 客户端池数据 修改
	if(['client', 'connected'].includes(key)){
		return getClientPool(global.clientList[idx].socket.soure)[global.clientList[idx].socket.clientId][key] = value;
	}
	global.clientList[idx][key] = value;
	return true;
}

//获取全局变量数据
const getGlobalData = (key, clientId) => {
	if(!key || !clientId) return null
	//获取 指定id 全局变量数据
	const idx = global.clientList.findIndex(item => item.socket.clientId === clientId);
	if(idx < 0 || !global.clientList[idx]) return null
	// 快手 抖音 客户端池数据
	if(['client', 'connected'].includes(key)){
		return getClientPool(global.clientList[idx].socket.soure)[global.clientList[idx].socket.clientId][key];
	}
	return global.clientList[idx][key];
}

//服务抖音获取wss链接 http://127.0.0.1:端口号/getDyWssUrl
//http postjson({RoomId:'',UserUniqueId:''}) 
app.post('/getDyWssUrl', async (req, res) => {
	const douyinWssServce = new douyinWssInfo();
	douyinWssServce.setConfig({
		liveRoomId: req?.body?.RoomId || '', // 直播房间ID
    	userUniqueId: req?.body?.UserUniqueId || '', // 用户唯一ID
	});
	const dyWssLink = await douyinWssServce.getWssUrl();
	res.status(200).json({code: 0, msg: 'success', data: dyWssLink});
})

app.listen(config.httpPort, () => {
	console.log(`Http Server: http://127.0.0.1:${config.httpPort}`);
})
